// a new bug in initialization a domain:
// dp[0].pre should be the last value
// 10 Apr

#include <math.h>
#include <errno.h>
#include <fstream>
#include <vector>
#include <list>

using namespace std;

// #include "csp_base.h"
#include "urbcsp.h"

//initializatin of a CSP
void CSP::setupCSP()
{
  int i, j, x;
  Domain *dp; 
  Constraint *cnp;

  //--------------- domains -----------------------
  // domain: .....[head 1st 2nd .... dth].....
  // We also assume the element is identical to its position, e.g.
  // 1 means element 1 and its stored position in the domain buffer. 
  //BackSupport.generateList(n,d,e);
  domain = new Domain [n * (d+1)];
  if (!domain) {
    printf("Memory error (domain)\n");
    exit (-1);
  }
  num_removed_values = 0; // number of values removed in AC-enforcing

  for (i = 0, dp = domain ; i < n; i++){
    dp[0].pre = d; // 10 Apr
 
    for (x = 0; x < d; x++) {
#ifdef BACK_POINT_SUPPORT
		(*dp).supported=NULL;
#endif
      (*dp).yes = 1;
      (*dp).next = x+1; // the link list of the values of var i
      dp++;
      (*dp).pre = x; 
      //(*dp).value = x+1; 
    }
#ifdef BACK_POINT_SUPPORT
	(*dp).supported=NULL;
#endif
    (*dp).yes = 1;
    (*dp).next = 0; // the end of the link list.
    dp++;
  }

  //---------------- variables  --------------------
  // variable is numbered for 0 to n-1
  
  vars = new Variable [n]; 
  for(i=0; i<n; i++) {
    vars[i].dp = domain + i*(d+1); 
    vars[i].domainSize = d; 
  }
  
  //---------------- constraints -------------------
  cn = new Constraint [n*n];
  if (!cn){
    printf("Memory error (cn)\n");
    exit (-1);
  }
  for (i = 0, cnp = cn; i < n; i++)
    for (j = 0; j < n; j++, cnp++){
      *cnp = NULL;
    }
}

CSP::~CSP()
{
  //cerr << "Destructor: URBCSP begin" << endl;
  int i, j;
  Constraint *cnp;

  delete [] domain; 
  delete [] vars; 
  for(i = 0, cnp = cn; i < n; i++)
    for(j = 0; j < n; j++, cnp++){
      if(*cnp != NULL) 
	delete [] *cnp;
    } // any constraint (i,j)
  delete [] cn;
  //cerr << "Destructor: URBCSP end" << endl;
}

// to check if (i,x) (j,y) satisfy the constraint between i and j.
// x, y are the indexes of the values!
bool CSP::validtuple(int i, int j, int x, int y)
{
  if( *(cn[i*n+j] + (x-1)*d + (y-1)) )
    return 1;
  else return 0;
}

// any constraint between i and j?

bool CSP::related(int i, int j)
{
  if (cn[i*n + j] != NULL) return 1;
  else return 0;
}

void CSP::setCurrentConstraint(int i, int j)
{
  currentc = cn[i*n + j];
}

bool CSP::validtuple(int x, int y)
{
  if ( *(currentc+ (x-1)*d + (y-1)) ) return true;
  else return false;
}

// print the CSP

void CSP::printcd(int i, int j, int x)
{
  Domain *dip, *djp;
  Constraint Pcurij;
  int y;

      printf("\n(%d, %d):", i, j);
      dip = domain + i*(d+1);
      djp = domain + j*(d+1);
        Pcurij = cn[i*n + j] + (x-1)*d;
        printf("support of (%d,%d) is:[ ", i, x);
        for( y = djp[0].next; y != 0; y = djp[y].next)
          if ( Pcurij[y-1] ) printf("%d", y);
        printf("]\n");
}

void CSP::printCSP()
{
  Domain *dip, *djp;
  Constraint Pcurij;
  int i, j, x, y;

  for(i = 0; i < n; i++)
    for(j = i+1; j < n; j++){
      if (cn[i*n+j] == NULL) continue;
      printf("\n(%d, %d):", i, j);
      dip = domain + i*(d+1);
      djp = domain + j*(d+1);
      for( x = dip[0].next; x != 0; x = dip[x].next){
	Pcurij = cn[i*n+j] + (x-1)*d;
	for( y = djp[0].next; y != 0; y = djp[y].next)
	  if ( Pcurij[y-1] ) printf("(%d,%d)", x, y);
      }
      printf("\n-------\n");
    }
}

#ifdef VAL_COMPUTE
void CSP::printVG()
{
  for(int i=0;i<n*d;i++)
  {
	  printf("\n(%d,%d):", i/d, i%d+1);
	  if(valConnect[i].size()==0)
		  cout << "No Connections" << endl;
	  else
		  for(list<int>::iterator iter=valConnect[i].begin();iter!=valConnect[i].end();iter++)
			  printf("(%d,%d)", (*iter)/d, (*iter)%d+1);
	  printf("\n-------\n");
  }
}
#endif

// destroy a CSP

CSP::CSP(int n1, int d1, int e1, int T, int *S)
{
  //cerr << "Constructor: URBCSP begin" << endl;
  //int i, j;

  n = n1; 
  d = d1;
  e = e1;

  setupCSP();

  std::cout << "[CSP::CSP] We are experimenting on RANDOM problems\n";
  
  //------ set up the constraints -------
  
  if (!makeURBCSP(n, d, e, T, S)){
    std::cout << "Cant generate the random csp\n";
    exit(1);
  }
  
  initCSP_base(); 
  //cerr << "Constructor: URBCSP end" << endl;
}

CSP::CSP(int n1, int d1)
{
  //int i, j;

  n = n1; 
  d = d1;
  e = n;

  setupCSP();

  std::cout << "[CSP::CSP] We are experimenting on DOMINO problems\n";

  if (!makeDomino(n, d)){
    std::cout << "Cant generate the domino csp\n";
    exit(1);
  }

  initCSP_base(); 
}

CSP::CSP(const char *filename)
{
	ifstream inTable(filename);
	int domainTypes;
	int relationTypes;
	if(!inTable)
	{
		cout << "Failure loading table file" << endl;
		exit(1);
	}
	cout << "Entered table" << endl;
	inTable >> domainTypes;
	inTable >> d;
	cout << "Found Max Domain size of " << d << endl;
	vector<list<int> > domains(domainTypes); //store domain types
	for(int curDom=0;curDom<domainTypes;curDom++)
	{
		int numDom;
		inTable >> numDom;
		for(int val=0;val<numDom;val++)
		{
			int domval;
			inTable >> domval;
			domains[curDom].push_back(domval);
		}
	}
	inTable >> n;
	//cout << "Finished loading domains." << endl;
	cout << "Found " << n << " variables." << endl;
	setupCSP();
	for(int var=0;var<n;var++) //crude but effective way to create variable sized domains
	{
		int useddom;
		inTable >> useddom;
		list<int>::iterator iter=domains[useddom].begin();
		for(int val=1;val<=d;val++)
		{
			while(*iter<val && iter!=domains[useddom].end()) iter++;
			if(iter==domains[useddom].end())
			{
				for(;val<=d;val++)
				{
					remove(var,val);
				}
				break;
			}
			if(*iter!=val)
			{
				//cout << "Value not in domain " << useddom << ", removing " << val << endl;
				remove(var,val);
			}
		}			
	}
	while(!removedValues.empty())removedValues.pop();//no need to store the removed values: they were never supposed to be there
	num_removed_values=0;
					
	//cout << "Finished loading variables and cleaned domains" << endl;
	inTable >> relationTypes;
	cout << "Found " << relationTypes << " relation types" << endl;
	vector<streampos> relationVector(relationTypes);
	//contains the position of the relation in the file.
	//requires far too much memory to store
	while(inTable.get()!='\xa');
	for(int rel=0;rel<relationTypes;rel++)
	{
		relationVector[rel]=inTable.tellg();
		while(inTable.get()!='\xa');
		//if(rel%100==0)
		//	cout << "On Relation " << rel << endl;
	}
	//cout << "Received offsets for relations" << endl;
	inTable >> e;
	cout << "Found " << e << " Edges" << endl;
	
	for(int cpair=0;cpair<e;cpair++)
	{
		//cout << "Adding Constraint " << cpair;
		int x,y,rel;
		inTable >> x;
		inTable >> y;
		//cout << " between Variables " << x << " and " << y;
		inTable >> rel;
		//cout << " using Relation " << rel << endl;
		int lastpos=inTable.tellg();
		inTable.seekg(relationVector[rel],ios::beg);
		//cout << "on edge " << cpair+1 << endl;
		//if(!inTable)
		//{
		//	cout << "Stream is bad." << endl;
		//	return;
		//}	
		{

			int type,relsize;
			inTable >> type;
			inTable >> relsize;
			//if(!inTable)
			//{
			//	cout << "Stream is bad." << endl;
			//	return;
			//}

			if(type==0)
			{
				//if (cpair==4102)
					//cout << "Conflict Constraint, size " << relsize << endl;
				AddConstraint(x,y);
				for(int tupl=0;tupl<relsize;tupl++)
				{
					int tupl1,tupl2;
					inTable >> tupl1;
					inTable >> tupl2;
					//if (cpair==4102)
					//{
					//	cout << "Removing bad tuple (";
					//	cout.flush();
					//}
					AddNogood(tupl1-1,tupl2-1);
					//if (cpair==4102)
						//cout << tupl1 << "," << tupl2 << ")" << endl;
				}
			}
			else
			{
				//cout << "Support Constraint, size " << relsize << endl;
				AddC(x,y);
				for(int tupl=0;tupl<relsize;tupl++)
				{
					int tupl1,tupl2;
					inTable >> tupl1;
					inTable >> tupl2;
					//if(!inTable)
					//{
					//	cout << "Stream is bad." << endl;
					//	return;
					//}
					//cout << "Adding Good tuple (";
					//cout.flush();
					AddGood(tupl1-1,tupl2-1);
					//cout << tupl1 << "," << tupl2 << ")" << endl;
				}
			}
		}
		//cout << " ...Done." << endl;
		inTable.seekg(lastpos);
	}
	initCSP_base();
	//printCSP();
}

void CSP::AddConstraint(int i, int j)
{
  int x, y;

  cn[ i*n + j ] = (Constraint) new char [d*d];
  cn[ j*n + i ] = (Constraint) new char [d*d];

  /*
  cn[ i*n + j ] = (Constraint) malloc (sizeof(char)*d*d);
  cn[ j*n + i ] = (Constraint) malloc (sizeof(char)*d*d);
  */

  if (!cn[ i*n + j ] || !cn[ j*n + i ]){
    printf ("Mem error (*cn) %d for constraint (%d,%d)\n", errno, i, j);
    exit(-1);
  }

  // initialize the constraint (i,j) ((j,i)) to be D_i X D_j (the inverse)

  for( x = 0, curij = cn[ i*n + j], curji = cn[j*n+i]; x < d; x++)
    for( y = 0; y < d; y++){
      *curij = 1;
      curij++; 
      *curji = 1;
      curji++;
    }
  curij = cn[ i*n + j]; // used by AddNogood
  curji = cn[ j*n + i];
}

void CSP::AddNogood(int x, int y)
{

// set (i,j)(x,y) to be invalid
// x,y:0..(d-1)

  curij[x*d+y] = 0;
  curji[y*d+x] = 0;

//  printf("(%d %d) ", val1, val2);

}

void CSP::AddC(int i, int j)
{
  int x, y;

  /*
  cn[ i*n + j ] = (Constraint) malloc (sizeof(char)*d*d);
  cn[ j*n + i ] = (Constraint) malloc (sizeof(char)*d*d);
  */

  cn[ i*n + j ] = (Constraint) new char [d*d];
  cn[ j*n + i ] = (Constraint) new char [d*d];

  if (!cn[ i*n + j ] || !cn[ j*n + i ]){
    printf ("Mem error (*cn) %d for constraint (%d,%d)\n", errno, i, j);
    exit(-1);
  }

// initialize the constraint (i,j) ((j,i)) to be empty

  for( x = 0, curij = cn[ i*n + j], curji = cn[j*n+i]; x < d; x++)
    for( y = 0; y < d; y++){
      *curij = 0;
      curij++; 
      *curji = 0;
      curji++;
    }
  curij = cn[ i*n + j]; // used by AddGood
  curji = cn[ j*n + i];
}

void CSP::AddGood(int x, int y)
{
// set (i,j)(x,y) to be valid
// x,y:0..(d-1)

  curij[x*d+y] = 1;
  curji[y*d+x] = 1;
}

//--------------------the following is DOMINO instances generator--

// This function generate the DOMINO problem 
// which involves a lot of propogation

int CSP::makeDomino(int n1, int d1)
{
  int x;
  int i;

  for( i=0; i < n1-1; i++) {
    AddC(i, i+1);
    for( x=0; x < d1; x++)
      AddGood(x, x);
  }

  AddC(n1-1, 0);
  for( x=0; x < d1-1; x++)
    AddGood(x, x+1);

  // The following pair will make the csp consistent one. O/W inconsistent
  AddGood(d1-1, d1-1);

  /* A special case of the above generation
  csp.AddC(0,1);
  for(x=0; x < d; x++)
    csp.AddGood(x,x);

  csp.AddC(1,2);
  for(x=0; x < d-1; x++)
    csp.AddGood(x, x+1);
  csp.AddGood(x, x); 

  csp.AddC(2,0);
  for(x=0; x < d-1; x++)
    csp.AddGood(x, x);
  */

  return 1;
}

//--------------------the following is the random instances generator--

/* CSP parameters */

// extern Constraint *cn, curij, curji;
// extern int n, d, e;

/* function declarations */
float ran2(int *idum);
// void AddConstraint(int var1, int var2);
// void AddNogood(int val1, int val2);

/*********************************************************************
  This file has 5 parts:
  0. This introduction.
  1. A main() function, which can be used to demonstrate makeURBCSP().
  2. makeURBCSP().
  3. ran2(), a random number generator.
  4. The four functions StartCSP(), AddConstraint(), AddNogood(), and
     EndCSP(), which are called by makeURBCSP().  The versions
     of these functions given here print out each instance, listing
     the incompatible value pairs of each constraint.  You will need
     to replace these functions with versions that mesh with your
     system and data structures.
*********************************************************************/

/*********************************************************************
  1. A simple main() function which reads in command line parameters
     and generates CSPs.
*********************************************************************/

// main function

/*********************************************************************
  2. makeURBCSP() creates a uniform binary constraint satisfaction
     problem with a specified number of variables, domain size,
     tightness, and number of constraints.  makeURBCSP() calls
     four functions, StartCSP(), AddConstraint(), AddNogood(), and
     EndCSP(), which actually create the CSP (that is, build a data
     structure).  Feel free to change the signatures of these functions.
     Note that numbering starts from 0: the variables are numbered 0..N-1,
     and the values are numbered 0..K-1.

  INPUT PARAMETERS:
   N: number of variables
   D: size of each variable's domain
   C: number of constraints
   T: number of incompatible value pairs in each constraint
   Seed: a negative number means start a new sequence of
      pseudo-random numbers; a positive number means continue
      with the same sequence.  S is turned positive by ran2().
  RETURN VALUE:
      Returns 0 if there is a problem; 1 for normal completion.
*********************************************************************/

int CSP::makeURBCSP(int N, int D, int C, int T, int *Seed)
{
  int PossibleCTs, PossibleNGs;       /* CT means "constraint" */
  unsigned int *CTarray, *NGarray;   /* NG means "nogood pair" */
  int selectedCT, selectedNG;
  int i, c, r, t;
  int var1, var2;
  static int instance;

  /* Check for valid values of N, D, C, and T. */
  if (N < 2)
    {
      printf("MakeURBCSP: ***Illegal value for N: %d\n", N);
      return 0;
    }
  if (D < 2)
    {
      printf("MakeURBCSP: ***Illegal value for D: %d\n", D);
      return 0;
    }
  if (C < 0 || C > N * (N - 1) / 2)
    {
      printf("MakeURBCSP: ***Illegal value for C: %d\n", C);
      return 0;
    }
  if (T < 1 || T > ((D * D) - 1))
    {
      printf("MakeURBCSP: ***Illegal value for T: %d\n", T);
      return 0;
    }

  if (*Seed < 0)      /* starting a new sequence of random numbers */
    instance = 0;
  else
    ++instance;       /* increment static variable */

//  initcsp(N, D, C);

  /* The program has to choose randomly and uniformly m values from
     n possibilities.  It uses the following logic for both constraints
     and nogood value pairs:
           1. Let t[] be an array of the n possibilities
           2. for i = 0 to m-1
           3.    r = random(i, n-1)    ; random() returns an int in [i,n-1]
           4.    swap t[i] and t[r]
           5. end-for
     At the end of the for loop, the elements from t[0] to t[m-1] are
     the m randomly selected elements.
   */

#ifdef DEBUG
  printf("MAKECSP mem allocation ... "); 
#endif
  /* Create an array for each possible binary constraint. */
  PossibleCTs = N * (N - 1) / 2;
//  CTarray = (unsigned long*) malloc(PossibleCTs * 4);
// 4 is changed to sizeof(long)
  CTarray = (unsigned int*) malloc(PossibleCTs * sizeof(int));
  /* Create an array for each possible value pair. */
  PossibleNGs = D * D;
  // NGarray = (unsigned long*) malloc(PossibleNGs * 4);
  NGarray = (unsigned int*) malloc(PossibleNGs * sizeof(int));

  /* Initialize the CTarray.  Each entry has one var in the high two
     bytes, and the other in the low two bytes. */
  i=0;
  for (var1=0; var1<(N-1); ++var1)
    for (var2=var1+1; var2<N; ++var2)
      CTarray[i++] = (var1 << 16) | var2;
  
  /* Select C constraints. */
  for (c=0; c<C; ++c)
    {
      /* Choose a random number between c and PossibleCTs - 1, inclusive. */
      r =  c + (int) (ran2(Seed) * (PossibleCTs - c));

      /* Swap elements [c] and [r]. */
      selectedCT = CTarray[r];
      CTarray[r] = CTarray[c];
      CTarray[c] = selectedCT;

      /* Broadcast the constraint. */
      AddConstraint((int)(CTarray[c] >> 16), (int)(CTarray[c] & 0x0000FFFF));

      /* For each constraint, select T illegal value pairs. */

      /* Initialize the NGarray. */
      for (i=0; i<(D*D); ++i)
        NGarray[i] = i;

      /* Select T incompatible pairs. */
      for (t=0; t<T; ++t)
        {
          /* Choose a random number between t and PossibleNGs - 1, inclusive.*/
          r =  t + (int) (ran2(Seed) * (PossibleNGs - t));
          selectedNG = NGarray[r];
          NGarray[r] = NGarray[t];
          NGarray[t] = selectedNG;

          /* Broadcast the nogood value pair. */
          AddNogood((int)(NGarray[t] / D), (int)(NGarray[t] % D));
        }
    }

  free(CTarray);
  free(NGarray);
  return 1;
}

/*********************************************************************
  3. This random number generator is from William H. Press, et al.,
     _Numerical Recipes in C_, Second Ed. with corrections (1994),
     p. 282.  This excellent book is available through the
     WWW at http://nr.harvard.edu/nr/bookc.html.
     The specific section concerning ran2, Section 7.1, is in
     http://cfatab.harvard.edu/nr/bookc/c7-1.ps
*********************************************************************/

#define IM1   2147483563
#define IM2   2147483399
#define AM    (1.0/IM1)
#define IMM1  (IM1-1)
#define IA1   40014
#define IA2   40692
#define IQ1   53668
#define IQ2   52774
#define IR1   12211
#define IR2   3791
#define NTAB  32
#define NDIV  (1+IMM1/NTAB)
#define EPS   1.2e-7
#define RNMX  (1.0 - EPS)

/* ran2() - Return a random floating point value between 0.0 and
   1.0 exclusive.  If idum is negative, a new series starts (and
   idum is made positive so that subsequent calls using an unchanged
   idum will continue in the same sequence). */

float ran2(int *idum)
{
  int j;
  int k;
  static int idum2 = 123456789;
  static int iy = 0;
  static int iv[NTAB];
  float temp;

  if (*idum <= 0) {                             /* initialize */
    if (-(*idum) < 1)                           /* prevent idum == 0 */
      *idum = 1;
    else
      *idum = -(*idum);                         /* make idum positive */
    idum2 = (*idum);
    for (j = NTAB + 7; j >= 0; j--) {           /* load the shuffle table */
      k = (*idum) / IQ1;
      *idum = IA1 * (*idum - k*IQ1) - k*IR1;
      if (*idum < 0)
        *idum += IM1;
      if (j < NTAB)
        iv[j] = *idum;
    }
    iy = iv[0];
  }

  k = (*idum) / IQ1;
  *idum = IA1 * (*idum - k*IQ1) - k*IR1;
  if (*idum < 0)
    *idum += IM1;
  k = idum2/IQ2;
  idum2 = IA2 * (idum2 - k*IQ2) - k*IR2;
  if (idum2 < 0)
    idum2 += IM2;
  j = iy / NDIV;
  iy = iv[j] - idum2;
  iv[j] = *idum;
  if (iy < 1)
    iy += IMM1;
  if ((temp = AM * iy) > RNMX)
    return RNMX;                                /* avoid endpoint */
  else
    return temp;
}

/*********************************************************************
  4. An implementation of StartCSP, AddConstraint, AddNogood, and EndCSP
     which prints out the CSP, just listing incompatible value pairs.
     Each constraint starts one a new line, and the id-numbers of the
     variables appear before the colon.  For instance, the output of
        urbcsp 10 5 4 3 9999 10
     begins
        Instance 0
          8   9: (1 1) (4 0) (0 4)
          2   4: (0 3) (3 1) (4 0)
          6   9: (4 1) (2 0) (0 3)
          1   5: (0 3) (4 0) (0 0)
*********************************************************************/

/*
  AddConstraint and AddNogood are provided by the object csp
 */



